package sfin.service;

import static org.apache.commons.lang.StringUtils.isBlank;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import sfin.swt.component.event.LancamentoFilterChangedEvent;
import sfin.swt.component.event.LancamentoFilterChangedListener;
import sfin.swt.filter.LancamentoFilter;
import br.com.statizo.financeiro.domain.entity.impl.Lancamento;
import br.com.statizo.financeiro.domain.enums.FormaPagamento;

@Component
public class LancamentoFilterService {

	private final List<Lancamento> lancamentos = new ArrayList<>();
	private final List<Lancamento> filtered = new ArrayList<Lancamento>();
	
	private List<LancamentoFilterChangedListener> listeners = new ArrayList<LancamentoFilterChangedListener>();
	private LancamentoFilter currentFilter;

	@Autowired
	private LancamentoService lancamentoService;
	
	private boolean isNecessaryReload(LancamentoFilter filter){
		if(filter.getYear() != currentFilter.getYear()){
			return true;
		}else if(filter.getMonth() != currentFilter.getMonth()){
			return true;
		}else if(!filter.getContaCorrente().equals(currentFilter.getContaCorrente())){
			return true;
		}
		return false;
	}
	
	private void reLoad(){
		lancamentos.clear();
		filtered.clear();
		lancamentos.addAll(lancamentoService.getLancamentos(currentFilter.getMonth(), currentFilter.getYear(), currentFilter.getContaCorrente().getId()));
		filtered.addAll(lancamentos);
	}
	
	public void doFilter(LancamentoFilter filter){
		if(isNecessaryReload(filter)){
			currentFilter = filter;
			reLoad();
		}
		

		for(int i = 0; i<lancamentos.size(); i++){

			Lancamento lancamento = lancamentos.get(i);
			boolean textOk = true;

			String filterText = filter.getText();
			if(!isBlank(filterText)){
				String normalizedDescr = lancamento.getDescricao().toLowerCase();
				String normalizedTextFilter = filter.getText().toLowerCase();
				textOk = normalizedDescr.matches(".*"+normalizedTextFilter+".*");
			}

			if(lancamento.isSaldo()){

				if(filter.getReceita() == null){

					if(textOk)
						filtered.add(lancamento);	

				}else{

					boolean saldoSaida = lancamento.isSaldoSaida(filter.getMonth(), filter.getYear());
					boolean recOk = (filter.getReceita() && !saldoSaida) || (!filter.getReceita() && saldoSaida);

					if(recOk && textOk)
						filtered.add(lancamento);
				}

			}else{
				boolean cardOk = filter.getCartao() == null || (Boolean.TRUE.equals(filter.getCartao()) && lancamento.getCartao() != null)
						|| (Boolean.FALSE.equals(filter.getCartao()) && lancamento.getCartao() == null);

				boolean moneyOk = filter.getDebito() == null || (Boolean.TRUE.equals(filter.getDebito()) && FormaPagamento.DINHEIRO.equals(lancamento.getFormaPagamento()));

				boolean checkOk = filter.getCheque() == null || (Boolean.TRUE.equals(filter.getCheque()) && FormaPagamento.CHEQUE.equals(lancamento.getFormaPagamento()));

				boolean transfOk = filter.getTranferencia() == null || (Boolean.TRUE.equals(filter.getTranferencia()) && FormaPagamento.TRANSFERENCIA.equals(lancamento.getFormaPagamento()));

				boolean pgOk = filter.getPg() == null || (Boolean.TRUE.equals(filter.getPg()) && lancamento.isPago())
						|| (Boolean.FALSE.equals(filter.getPg()) && !lancamento.isPago());

				boolean recOk = filter.getReceita() == null || (Boolean.TRUE.equals(filter.getReceita()) && lancamento.isReceita())
						|| (Boolean.FALSE.equals(filter.getReceita()) && !lancamento.isReceita());

				boolean agendOk = !filter.isAgend() || (filter.isAgend() && lancamento.isAgendado());


				if(cardOk && moneyOk && checkOk && transfOk && pgOk && recOk && textOk && agendOk)
					filtered.add(lancamento);
			}

		}
		
		notifyAllListeners(filter);
	}
	
	public List<Lancamento> getLancamentos() {
		return lancamentos;
	}
	
	public void sortByPgtoDate(){
	  lancamentos.sort((l1,l2) -> l1.getDataPagamento().compareTo(l2.getDataPagamento()));
	}
	
	public void addListener(LancamentoFilterChangedListener listener){
		if(!listeners.contains(listener)){
			listeners.add(listener);
		}
	}
	
	public void removeListener(LancamentoFilterChangedListener listener){
		if(listeners.contains(listener)){
			listeners.remove(listener);
		}
	}
	
	private void notifyAllListeners(LancamentoFilter filter){
		LancamentoFilterChangedEvent evt = new LancamentoFilterChangedEvent();
		evt.filter = filter;
		evt.result = filtered;
		
		for(int i = 0; i<listeners.size(); i++){
			listeners.get(i).filterChanged(evt);
		}
	}
	
}